﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#ifndef _UXS_CL_COMMON_H
#define _UXS_CL_COMMON_H

#pragma once

#include "CLEnums.h"
#include "../../OS/Base/OSTypes.h"

namespace UX_STL
{
namespace CLShell
{
	

#ifndef OPENGL_ONLY
# ifdef _UXS_USE_OPENGL
#	define OPENGL_ONLY		ARGS
# else
#	define OPENGL_ONLY		__UX_EMPTY_ARGS
# endif
#endif

#ifndef DIRECTX_ONLY
# ifdef _UXS_USE_DIRECTX
#	define DIRECTX_ONLY		ARGS
# else
#	define DIRECTX_ONLY		__UX_EMPTY_ARGS
# endif
#endif


	//class CLDevice;
	class CLQueue;
	class CLEvent;
	class CLKernel;
	class CLProgram;
	class CLMemory;
	class CLBuffer;
	class CLImage;
	class CLSampler;
	struct CLEventArray;
	struct CLMemObjArray;



	//
	// CL Events Universal Array
	//

	struct clevent_uni_array : public uni_array< cl_event >
	{
		typedef uni_array< cl_event >		__parent_t;

		clevent_uni_array(): __parent_t( (cl_event *)null, 0 ) {}
		clevent_uni_array(cl_event *pEv, usize uCount): __parent_t( pEv, uCount ) {}

		template <typename S, typename A>
		clevent_uni_array(const array<cl_event,S,A> &sArr): __parent_t( (cl_event *)sArr.ptr(), sArr.Count() ) {}

		operator		__parent_t ()			{ return __parent_t( ptr(), Count() ); }
		operator const	__parent_t () const		{ return __parent_t( (cl_event *)ptr(), Count() ); }
	};

	
	//
	// CL Memory Objects Universal Array
	//

	struct clmem_uni_array : public uni_array< cl_mem >
	{
		typedef uni_array< cl_mem >		__parent_t;

		clmem_uni_array(): __parent_t( (cl_mem *)null, 0 ) {}
		clmem_uni_array(cl_mem *pMem, usize uCount): __parent_t( pMem, uCount ) {}
		
		template <typename S, typename A>
		clmem_uni_array(const array<cl_mem,S,A> &sArr): __parent_t( (cl_mem *)sArr.ptr(), sArr.Count() ) {}

		operator		__parent_t ()			{ return __parent_t( ptr(), Count() ); }
		operator const	__parent_t () const		{ return __parent_t( (cl_mem *)ptr(), Count() ); }
	};


#ifdef UX_CL_BASEOBJECT_OVERRIDE
	UX_CL_BASEOBJECT_OVERRIDE
#else
# ifndef UX_CL_BASEOBJECT_DEFINED


	//
	// Base Object
	//

	class UX_EXPORT CLBaseObject
	{
	/*protected:
		virtual void _RetainRef()	const = 0;
		virtual void _ReleaseRef()	const = 0;
		virtual uint _GetRefCount()	const = 0;
		virtual void _Destroy() = 0;*/

	private:
		CLBaseObject(const CLBaseObject &) {}
		void operator = (const CLBaseObject &) {}

	public:
		CLBaseObject() {}
		virtual ~CLBaseObject() {}
	};

# endif	// UX_CL_BASEOBJECT_DEFINED
#endif	// UX_CL_BASEOBJECT_OVERRIDE


#define __UX_CL_RC_IMPL(_class, _id, _name, _NAME) \
	/*
	=================================================
		увеличить количество ссылок на объект
	=================================================
	*/ \
	void _class::_RetainRef() const \
	{ \
		if ( _id != null ) { \
			CL_CALL( cl_int  i_cl_err = clRetain##_name( _id ) ); \
		} \
	} \
	/*
	=================================================
		уменьшить количество ссылок на объект
	=================================================
	*/ \
	void _class::_ReleaseRef() const \
	{ \
		if ( _id != null ) { \
			CL_CALL( cl_int  i_cl_err = clRelease##_name( _id ) ); \
		} \
	} \
	/*
	=================================================
		возвращает количество ссылок на объект
	=================================================
	*/ \
	uint _class::_GetRefCount() const \
	{ \
		cl_uint			u_count	= 0; \
		CL_CALL( cl_int  i_cl_err = clGet##_name##Info( _id, CL_##_NAME##_REFERENCE_COUNT, sizeof(cl_uint), &u_count, null ) ); \
		return u_count; \
	} \
	/*
	=================================================
		удаляет объект не зависимо от количества
		ссылок на него
	=================================================
	*/ \
	void _class::_Destroy() \
	{ \
		if ( _id == null ) \
			return; \
		\
		cl_int		i_cl_err = 0; \
		cl_uint		u_count	 = 0; \
		bool		res		 = true; \
		\
		CL_CALL( i_cl_err = clGet##_name##Info( _id, CL_##_NAME##_REFERENCE_COUNT, sizeof(cl_uint), &u_count, null ) ); \
		\
		for (uint i = 0; (i < u_count and res); ++i) { \
			CL_CALL_B( i_cl_err = clRelease##_name( _id ), res ); \
		} \
		_id = null; \
	}
	
//-------------------------------------------------------------------

}	// CLShell
}	// UX_STL

#endif	// _UXS_CL_COMMON_H